package com.aplink.generic.widgets;

import java.util.ArrayList;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.Spinner;

import com.aplink.generic.GenericFragment;
import com.aplink.generic.adapter.ConfigAdapter;
import com.aplink.generic.database.SqlMethods;
import com.aplink.generic.dictionary.GenericDictionary;
import com.aplink.generic.interfaces.OnGetObjProInfo;
import com.aplink.generic.pojo.ColumnSetting;
import com.aplink.generic.pojo.ContentData;
import com.aplink.generic.pojo.GenericAttribute;
import com.aplink.generic.pojo.GenericObject;
import com.aplink.generic.pojo.ObjPropInfo;
import com.aplink.generic.pojo.Value;
import com.aplink.generic.pojo.controlspec.ControlSpec;
import com.aplink.generic.pojo.controlspec.spinner.SpinnerSpec;
import com.aplink.generic.util.ResourcesHelper;
import com.aplink.generic.util.validation.ValidationResult;
import com.aplink.generic.xmlparser.ColumnSettingParser;
import com.aplink.generic.xmlparser.ContentDataParser;

public class ApLinkSpinner extends ApLinkBaseView implements OnClickListener,
        OnItemSelectedListener, OnGetObjProInfo {
    private static final long serialVersionUID = 8303880571538132632L;
    private ArrayList<ColumnSetting> columnSettings;
    private BaseAdapter mBaseAdapter;
    private ContentData mContentData;
    private String mDefaultValue;
    private GenericDictionary<String, GenericAttribute> mListAttribute;
    private ArrayList<GenericObject> mListObjects;

    private Spinner mSpinner;

    private final SpinnerSpec mSpinnerSpec;

    public ApLinkSpinner(final GenericFragment dataEntryActivity,
            final ControlSpec controlSpec, final View view) {
        super(dataEntryActivity, controlSpec, view);
        setSpinner((Spinner) view);
        this.mSpinnerSpec = (SpinnerSpec) controlSpec;
        this.mContentData = new ContentData();
        this.mListObjects = new ArrayList<GenericObject>();
    }

    private void addNewItemRecord() {
        final GenericObject genericObject = new GenericObject();
        genericObject.put(this.mSpinnerSpec.getDataObject() + "."
                + this.mSpinnerSpec.getDisplayProperty(),
                this.mSpinnerSpec.getNewRowItem());
        this.mListObjects.add(genericObject);
    }

    private void addToFirst(final String value) {
        final GenericObject genericObject = new GenericObject();
        genericObject.put(this.mSpinnerSpec.getDataObject() + "."
                + this.mSpinnerSpec.getDisplayProperty(), value);
        final ArrayList<GenericObject> arrayList = new ArrayList<GenericObject>();
        arrayList.add(genericObject);
        arrayList.addAll(this.mListObjects);
        this.mListObjects = arrayList;
        setAdapet();
        this.mSpinner.setAdapter(this.mBaseAdapter);
        this.mSpinner.setSelection(0);
    }

    @Override
    public void clear() {

    }

    private ConfigAdapter generateConfigAdapter() {
        this.columnSettings = ColumnSettingParser.parse(getGenericFragment(),
                this.mSpinnerSpec.getRptrdesignID());
        return new ConfigAdapter(getGenericFragment(), this.mListObjects,
                this.columnSettings, this.mSpinnerSpec.getRowItem());
    }

    @Override
    public GenericAttribute getAttribute() {
        final ObjPropInfo primaryKey = this.mContentData.getPrimaryKeys()
                .get(0);
        final String columnNameContentData = primaryKey.getFullColumnName();
        final ObjPropInfo objPropInfo = this.mContentData
                .get(columnNameContentData);
        final int selectedPosition = this.mSpinner.getSelectedItemPosition();
        final GenericObject genericObject = this.mListObjects
                .get(selectedPosition);
        return GenericAttribute.obtain(
                genericObject.getValue(columnNameContentData), objPropInfo);
    }

    public String getDefaultValue() {
        return this.mDefaultValue;
    }

    @Override
    public GenericDictionary<String, GenericAttribute> getListAttributes() {
        return this.mListAttribute;
    }

    public GenericObject getSelectedItem() {
        final int index = this.mSpinner.getSelectedItemPosition();
        return this.mListObjects.get(index);
    }

    private String getSelectedMappingName() {
        final int selectedIndex = this.mSpinner.getSelectedItemPosition();
        final GenericObject selectedObject = this.mListObjects
                .get(selectedIndex);
        final String valueColumn = this.mValueList.getValueColumn();
        final String value = selectedObject.getValue(valueColumn).toString();
        return this.mValueList.get(value).getMappingName();
    }

    public String getSelectedValue() {
        return this.mSpinner.getSelectedItem().toString();
    }

    public Spinner getSpinner() {
        return this.mSpinner;
    }

    @Override
    public Spinner getView() {
        return this.mSpinner;
    }

    @Override
    protected void initViewProperties() {
        final boolean isVisibility = this.mSpinnerSpec.isVisibility();
        if (!isVisibility) {
            this.mSpinner.setVisibility(View.GONE);
        }
        this.mSpinner.setTag(this.mSpinnerSpec);

        if (this.mContentData.isEmpty()) {
            this.mContentData = ContentDataParser.getInstance()
                    .parseIntoObjProp(this.mSpinnerSpec.getContentDataID());
        }

        if (hasValueList()) {
            this.mListAttribute = new GenericDictionary<String, GenericAttribute>();
        }
    }

    @Override
    protected void loadBindingObject() {
        String whereConditions = null;
        if ((getRefreshConditions() != null)
                && !this.mSpinnerSpec.isLoadByConfig()) {
            whereConditions = getRefreshConditions();
        }

        this.mListObjects = loadData(whereConditions);

        final String mappingName = this.mSpinnerSpec.getDataObject() + "."
                + this.mSpinnerSpec.getMappingName();
        final String selectedValue = getHashPassedValues().get(mappingName);
        final String selectedColumn = String.format("%s.%s", this.mListObjects
                .get(0).getTableName(), this.mSpinnerSpec.getMappingName());
        int index = -1;
        for (int i = 0; i < this.mListObjects.size(); i++) {
            final GenericObject genericObject = this.mListObjects.get(i);
            final String value = genericObject.getValue(selectedColumn)
                    .toString();
            if (value.equalsIgnoreCase(selectedValue)) {
                index = i;
                break;
            }
        }
        if (this.mListObjects != null) {
            if (this.mSpinnerSpec.getRptrdesignID() == ResourcesHelper.RESOURCE_NOT_FOUND) {
                setAdapet();
            } else {
                this.mBaseAdapter = generateConfigAdapter();
            }
        }

        if (hasValueList()) {
            // mValueList
            final String dataObj = this.mValueList.getDataObj();
            for (int i = 0; i < this.mValueList.size(); i++) {
                final Value value = this.mValueList.valueAt(i);
                final String columnName = dataObj + "."
                        + value.getMappingName();
                final String realValue = getPassedGenericObject().getValue(
                        columnName);
                final ObjPropInfo objPropInfo = getGenericFragment()
                        .getContentData().get(columnName);
                final GenericAttribute attribute = GenericAttribute.obtain(
                        realValue, objPropInfo);
                this.mListAttribute.put(columnName, attribute);
            }
        }
        mergeStaticResource();
        this.mSpinner.setAdapter(this.mBaseAdapter);

        if (this.mSpinnerSpec.isHasNewRowItem()) {
            if (index == -1) {
                addToFirst(selectedValue);
                this.mSpinner.setSelection(0);
            }
        } else {
            this.mSpinner.setSelection(index);
        }
    }

    protected ArrayList<GenericObject> loadData(final String whereConditions) {
        this.mListObjects = getDatabaseGet().getList(this.mContentData,
                whereConditions);
        if (this.mSpinnerSpec.isHasNewRowItem()) {
            addNewItemRecord();
        }
        if (hasValueList()) {
            mergeStaticResource();
        }
        return this.mListObjects;
    }

    @Override
    protected void loadDefaultObject() {
        String whereConditions = null;
        if ((getRefreshConditions() != null)
                && !this.mSpinnerSpec.isLoadByConfig()) {
            whereConditions = getRefreshConditions();
        }
        this.mListObjects = loadData(whereConditions);

        if (this.mListObjects != null) {
            if (this.mSpinnerSpec.getRptrdesignID() == ResourcesHelper.RESOURCE_NOT_FOUND) {
                setAdapet();
            } else {
                this.mBaseAdapter = generateConfigAdapter();
            }
        }
        this.mSpinner.setAdapter(this.mBaseAdapter);
    }

    private void mergeStaticResource() {
        if (hasValueList()) {
            final String dataObj = this.mValueList.getDataObj();
            final String column = this.mValueList.getValueColumn();
            for (int i = 0; i < this.mListObjects.size(); i++) {
                final GenericObject object = this.mListObjects.get(i);
                final String value = object.get(column).getValue().toString();
                final String mappingName = this.mValueList.get(value)
                        .getMappingName();
                final GenericAttribute attribute = this.mListAttribute
                        .get(dataObj + "." + mappingName);
                object.put(ColumnSetting.STATIC_RESOURCE, attribute);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void setAdapet() {
        final String[] arrTextValue = new String[this.mListObjects.size()];
        final String fullColumnName = this.mContentData.getMainTable() + "."
                + this.mSpinnerSpec.getDisplayProperty();
        for (int i = 0; i < this.mListObjects.size(); i++) {
            final GenericObject genericObject = this.mListObjects.get(i);
            final String value = genericObject.getValue(fullColumnName)
                    .toString();
            arrTextValue[i] = value;
        }

        this.mBaseAdapter = new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_spinner_item, arrTextValue);
        ((ArrayAdapter<String>) mBaseAdapter)
                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    }

    public void setDefaultValue(final String defaultValue) {
        this.mDefaultValue = defaultValue;
    }

    @Override
    protected void setEventListener() {
        this.mSpinner.setOnItemSelectedListener(this);
        if (hasValueList()) {
            setClickEvent(this.mValueList.getSubmitControl(), this);

            final String resultControlID = this.mValueList.getValueControl();
            final ControlSpec specValueControl = getGenericFragment()
                    .getFormDesign().get(resultControlID);
            specValueControl.setOnGetObjProInfo(this);

            final ApLinkBaseView resultControl = getGenericFragment()
                    .getAPLinkViewByID(resultControlID);
            if (resultControl != null) {
                resultControl.setObjPropInfoTemp(this);
            }
        }
    }

    private void setClickEvent(String targetControlID,
            OnClickListener onClickListener) {
        ApLinkBaseView baseView = null;
        if (!TextUtils.isEmpty(targetControlID)) {
            baseView = getGenericFragment().getAPLinkViewByID(targetControlID);
            if (baseView != null) {
                baseView.setOnClickListener(onClickListener);
            } else if (getGenericFragment().getFormDesign()
                    .get(targetControlID) != null) {
                getGenericFragment().getFormDesign().get(targetControlID)
                        .setOnClickListener(onClickListener);
            } else if (getGenericFragment().findViewByID(targetControlID) != null) {
                getGenericFragment().findViewByID(targetControlID)
                        .setOnClickListener(onClickListener);
            }
        }
    }

    @Override
    public void setObjPropInfoTemp(final OnGetObjProInfo getObjProInfo) {
        throw new UnsupportedOperationException(this.getClass().getSimpleName()
                + " is not support this method");
    }

    @Override
    public void setOnClickListener(final OnClickListener onClickListener) {
        throw new UnsupportedOperationException(this.getClass().getSimpleName()
                + " is not support this method");
    }

    public void setSpinner(final Spinner spinner) {
        this.mSpinner = spinner;
    }

    @Override
    public void onClick(View v) {
        final ControlSpec controlSpec = (ControlSpec) v.getTag();
        final ValidationResult result = ApLinkSpinner.this.getGenericFragment()
                .isFormValidate(controlSpec);
        if (result.isValid()) {
            String value = null;
            final View valueControl = ApLinkSpinner.this.getValueControl();
            if (valueControl instanceof EditText) {
                value = ((EditText) valueControl).getText().toString();
            }
            final String dataObj = ApLinkSpinner.this.mValueList.getDataObj();
            final String mappingName = ApLinkSpinner.this
                    .getSelectedMappingName();

            final ObjPropInfo objPropInfo = ApLinkSpinner.this
                    .getGenericFragment().getContentData()
                    .get(dataObj + "." + mappingName);
            final GenericAttribute attribute = GenericAttribute.obtain(value,
                    objPropInfo);
            ApLinkSpinner.this.mListAttribute.put(dataObj + "." + mappingName,
                    attribute);
            if (ApLinkSpinner.this.hasValueList()) {
                ApLinkSpinner.this.mergeStaticResource();
                ApLinkSpinner.this.mBaseAdapter.notifyDataSetChanged();
            }
            ((EditText) valueControl).getText().clear();
        } else {
            ApLinkSpinner.this.getGenericFragment()
                    .showInvalidValidationDialog(controlSpec.getActionType(),
                            result);
        }
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position,
            long id) {
        if (ApLinkSpinner.this.mSpinnerSpec.getRefreshControl() != null) {
            final String refreshViewID = ApLinkSpinner.this.mSpinnerSpec
                    .getRefreshControl();
            final ApLinkBaseView baseView = ApLinkSpinner.this
                    .getGenericFragment().getAPLinkViewByID(refreshViewID);
            final String refreshValue = ApLinkSpinner.this.mSpinnerSpec
                    .getRefreshValue();
            final GenericAttribute selectedAttribute = ApLinkSpinner.this
                    .getAttribute();
            final SqlMethods sqlMethods = SqlMethods.getInstance();
            sqlMethods.equal(refreshValue, selectedAttribute.getValue()
                    .toString());
            baseView.setRefreshConditions(sqlMethods.toString());
            baseView.notifyDataSetChanged();
        }

        if (ApLinkSpinner.this.mSpinnerSpec.isHasNewRowItem()) {
            if (position == (ApLinkSpinner.this.mListObjects.size() - 1)) {
                final AlertDialog.Builder builder = new AlertDialog.Builder(
                        ApLinkSpinner.this.getActivity());
                final EditText editText = new EditText(
                        ApLinkSpinner.this.getActivity());
                final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
                editText.setLayoutParams(layoutParams);
                builder.setView(editText);
                builder.setTitle(ApLinkSpinner.this.mSpinnerSpec
                        .getNewRowItem());
                builder.setCancelable(false).setPositiveButton("OK",
                        new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(final DialogInterface dialog,
                                    final int which) {
                                if (which == DialogInterface.BUTTON_POSITIVE) {
                                    ApLinkSpinner.this.addToFirst(editText
                                            .getText().toString());
                                }
                            }
                        });
                builder.create().show();
            }
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }

    @Override
    public ObjPropInfo getObjProInfoTemp() {
        final String databObj = ApLinkSpinner.this.mValueList.getDataObj();
        final String mappingName = ApLinkSpinner.this.getSelectedMappingName();
        return ApLinkSpinner.this.getGenericFragment().getContentData()
                .get(databObj + "." + mappingName);
    }
}
